/****************************************
* James Gomez                           *
* Project 3: Target Practice P3         *
* Comp 465                              *
* Professor Barnes                      *
* 12/7/2012                             *
*****************************************/

#ifndef _GOMEZ_JAMES_MAIN_
#define _GOMEZ_JAMES_MAIN_

#include <iostream>
#include <stdlib.h>
#include <string>
#include <vector>

#include "GomezJamesP3_OpenGL.h"
#include "GomezJamesP3_Colors.h"
#include "GomezJamesP3_GlobalConsts.h"
#include "GomezJamesP3_MatrixLib.h"

#include "GomezJamesP3_PlayerShip.cpp"
#include "GomezJamesP3_Sun.cpp"
#include "GomezJamesP3_Planet.cpp"
#include "GomezJamesP3_Moon.cpp"
#include "GomezJamesP3_Torpedo.cpp"
#include "GomezJamesP3_Missile.cpp"
#include "GomezJamesP3_ShipTorpedo.cpp"
#include "GomezJamesP3_Camera.cpp"
#include "GomezJamesP3_ChaseCamera.cpp"

using namespace std;

//====================== GLOBAL VARS =============================
GLint parentWindow, gameWindow, topViewWindow, infoWindow, timeQuantum;
bool gravityOn;

//cameras
Camera * topCamera;
Camera * currentCamera;
vector <Camera *> allCameras;
vector<Camera *> frontShipCameras;
vector<ChaseCamera *> planetCameras;
vector<ChaseCamera *> chaseCameras;
vector<Camera *>::iterator frontShipCamIterator;
vector<ChaseCamera *>::iterator planetCamIterator;
vector<ChaseCamera *>::iterator warpIterator;
GLboolean lastSelectedCamType = FRONT_SHIP_VIEW;

//3d objects
Sun * ruber;
vector<Planet *> planets;
vector<Moon *> moons;
vector<MissileBattery *> missileSites;
PlayerShip * warbird;
PlayerShip * getExternWarbird(){ return warbird; };
vector<Torpedo *> torpedos;

//message buffer
char info[NUM_MSGS][MSG_LENGTH];

//key buffer
GLboolean keyBuffer[5];
enum {UP_KEY, DOWN_KEY, LEFT_KEY, RIGHT_KEY, CTRL_KEY};


//======================= PROTOTYPES =============================
void resizeParent(int, int);
void resizeGame(int, int);
void resizeTopView(int, int);
void resizeInfo(int, int);

void drawParent();
void drawGame();
void drawTopView();
void drawPlanets();
void drawMoons();
void drawMissileSites();
void drawTorpedos();
void drawCameras();
void drawLineCoordinates();
void drawInfo();

void initInfo();
void setGameInfo();
void printText();

void toggleGravity(bool gravity);

void keyDown(unsigned char, int, int);
void specialDown(int, int, int);
void specialUp(int, int, int);
void executeSpecialKeys();

void updateAll(int);
void updatePlanets();
void updateMoons();
void updateMissileSites();
void updateTorpedos();
void updateChaseCameras();

void checkForCollisions();
void checkTorpedoCollisions();
void checkWarbirdCollisions();

void createSpaceObjects();
void createCameras();

void setCurrentCamera();
void toggleFrontShipCamera();
void togglePlanetCamera();

void setLighting();

void redisplayAll();

void cleanUpAndExit();
void deleteCameras();
void deleteTorpedos();
void deleteMissileSites();
void deleteMoons();
void deletePlanets();


//======================= IMPLEMENTATION ==========================
int main (int argc, char * argv[]){
	// initialize parent window
	glutInit(&argc, argv);
	glutInitDisplayMode(GLUT_RGB|GLUT_DOUBLE|GLUT_DEPTH);
	glutInitWindowSize(PARENT_WIDTH, PARENT_HEIGHT);
	glutInitWindowPosition(PARENT_X, PARENT_Y);
	
	// make parent window
	parentWindow = glutCreateWindow("Romulan Target Practice");		
	glutReshapeFunc(resizeParent);
	glutDisplayFunc(drawParent);	

	// make game window
	glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH);
	gameWindow = glutCreateSubWindow(parentWindow, GAME_X, GAME_Y, GAME_WIDTH, GAME_HEIGHT);	
	glutReshapeFunc(resizeGame);
	glutDisplayFunc(drawGame); 
	glutKeyboardFunc(keyDown);
	glutSpecialFunc(specialDown);
	glutSpecialUpFunc(specialUp);
	
	// make top view window
	glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH);
	topViewWindow = glutCreateSubWindow(parentWindow, TOP_X, TOP_Y, TOP_WIDTH, TOP_HEIGHT);
	glutReshapeFunc(resizeTopView);
	glutDisplayFunc(drawTopView);   
	
	// make data window
	glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH);
	infoWindow = glutCreateSubWindow(parentWindow, INFO_X, INFO_Y, INFO_WIDTH, INFO_HEIGHT);
	glutReshapeFunc(resizeInfo);
	glutDisplayFunc(drawInfo); 

	timeQuantum = ACE;
	glutTimerFunc(timeQuantum, updateAll, 1); 
			
	createSpaceObjects();	

	createCameras();
	frontShipCamIterator = frontShipCameras.begin();
	planetCamIterator = planetCameras.begin();
	warpIterator = planetCameras.begin();

	gravityOn = true;
	toggleGravity(true);

	initInfo();	
	
	glutMainLoop();

	return 0;
}


void resizeParent(int width, int height){
	// don't let window resize -- restore postion and size
	if (width != PARENT_WIDTH && height != PARENT_HEIGHT){
		glutPositionWindow(PARENT_X, PARENT_X);
		glutReshapeWindow(PARENT_WIDTH, PARENT_HEIGHT);
	}
	
	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();
	glOrtho(-width/2, width, -height/2, height, -1000, 1000.0);
}

void resizeGame(int width, int height){
	glViewport(0, 0, width, height);
	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();
	gluPerspective(45.0, (float)width/(float)height, 150.0, 100000);
}

void resizeTopView(int width, int height){
	glViewport(0, 0, width, height);
	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();
	gluPerspective(60.0, (float)width/(float)height, 150.0, 100000);
}

void resizeInfo(int width, int height){
	glViewport(0, 0, width, height);
	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();
	glOrtho(-width/2.0, width, -height/2.0, height, -1.0, 1.0);
}

void drawParent(){		
	glClearColor(0.4, 0.4, 0.4, 0.0);
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);					
	glutSwapBuffers();
}

void drawGame(){	
	glClearColor(0.0, 0.0, 0.0, 1.0);
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
	glEnable(GL_DEPTH_TEST);			

	glMatrixMode(GL_MODELVIEW);	
	setCurrentCamera();

	setLighting();
	//drawLineCoordinates();	
	ruber->draw();
	warbird->draw();
	drawPlanets();
	drawMoons();
	drawMissileSites();
	drawTorpedos();
	//drawCameras();
	glutSwapBuffers();
}

void drawTopView(){	
	glClearColor(0.0, 0.0, 0.0, 0.0);
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
	glEnable(GL_DEPTH_TEST);	
	
	glMatrixMode(GL_MODELVIEW);	
	topCamera->setCameraView(); //load matrix for this camera
	
	setLighting();
	//drawLineCoordinates();	
	ruber->draw();
	warbird->draw();
	drawPlanets();
	drawMoons();
	drawMissileSites();
	drawTorpedos();
	//drawCameras();
	glutSwapBuffers();
}

void drawPlanets(){
	if (!planets.empty()){
		vector<Planet*>::iterator i;
		for (i=planets.begin(); i<planets.end(); i++)
			(*i)->draw();
	}
}

void drawMoons(){
	if (!moons.empty()){
		vector<Moon*>::iterator i;
		for (i=moons.begin(); i<moons.end(); i++)
			(*i)->draw();
	}	
}

void drawMissileSites(){
	if (!missileSites.empty()){
		vector<MissileBattery*>::iterator i;
		for (i=missileSites.begin(); i<missileSites.end(); i++)
			(*i)->draw();
	}	
}

void drawTorpedos(){
	if (!torpedos.empty()){
		vector<Torpedo *>::iterator i;
		for (i=torpedos.begin(); i<torpedos.end(); i++)
			(*i)->draw();
	}	
}

/* FOR DEBUGGING */
void drawCameras(){
	if (!allCameras.empty()){
		vector<Camera *>::iterator i;
		for (i=allCameras.begin(); i<allCameras.end(); i++)
			(*i)->draw();
	}	
}

/* FOR DEBUGGING */
void drawLineCoordinates(){
/* Draw line coordinates to help visualize coordinate system. */

	glColor3fv(red);
	glBegin(GL_LINES);
		glVertex3f(-21000,0,0);
		glVertex3f(21000,0,0);
	glEnd();

	glColor3fv(green);
	glBegin(GL_LINES);
		glVertex3f(0,-21000,0);
		glVertex3f(0,21000,0);
	glEnd();

	glColor3fv(blue);
	glBegin(GL_LINES);
		glVertex3f(0,0,-21000);
		glVertex3f(0,0,21000);
	glEnd();
}

void drawInfo(){
	static int frameCounter;

	/* draw info once every 25 frames */

	if (frameCounter == 1){
		frameCounter++;

		glutSetWindow(infoWindow);
		glClearColor(0.05, 0.05, 0.05, 0.0);
		glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
		
		glMatrixMode(GL_MODELVIEW);
		glLoadIdentity();
		glDisable(GL_LIGHTING);
	
		glColor3fv(green);
		setGameInfo();	//reset info in info buffer
		printText();	//display info buffer
					
		glEnable(GL_LIGHTING);
		glutSwapBuffers();
	}
	else if (frameCounter == 25) frameCounter = 1;
	else frameCounter++;


	/* draw info for every frame */

	//glutSetWindow(infoWindow);
	//glClearColor(0.05, 0.05, 0.05, 0.0);
	//glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
	//
	////draw to flat screen
	//glMatrixMode(GL_MODELVIEW);
	//glLoadIdentity();
	//glDisable(GL_LIGHTING);
	//
	//glColor3fv(green);
	//setGameInfo();
	//showText();
	//				
	//glEnable(GL_LIGHTING);
	//glutSwapBuffers();

}

void initInfo(){	
	//initialize info buffer to whitespace
	for (int i=0; i<NUM_MSGS; i++)
		for (int j=0; j<MSG_LENGTH; j++)
			info[i][j] = ' ';

	//set info titles
	sprintf(info[0], "Level: X            ");
	sprintf(info[2], "Camera: Front View  ");
	sprintf(info[3], "   xxxxx yyyyy zzzzz");
	sprintf(info[5], "Warbird:     nnn    ");
	sprintf(info[6], "   xxxxx yyyyy zzzzz");
	sprintf(info[8], "U.Missile:   nnn    ");
	sprintf(info[9], "   xxxxx yyyyy zzzzz");
	sprintf(info[11],"T.Missile:   nnn    ");
	sprintf(info[12],"   xxxxx yyyyy zzzzz");
}

void setGameInfo(){
	enum {UNUM, DUO, TRES, QUATTUOR};
	enum {PRIMUN, SECUNDO, TERTIA, QUARTUM};
	enum {U_MISSILE, T_MISSILE};
	enum {LEVEL = 0, CAM_NAME=2, CAM_LINE=3, WAR_LINE=6, U_MISS_LINE=9, T_MISS_LINE=12};

	char msgBuffer[MSG_LENGTH+1];
	GLfloat x, y, z;

	//write current difficulty level and fps info buffer (TODO: consider checking this on every frame)
	char levelString[8];
	switch (timeQuantum){
		case ACE: 			
			strcpy(levelString, "ACE");	break;
		case PILOT: 
			strcpy(levelString, "PILOT"); break;
		case TRAINEE: 
			strcpy(levelString, "TRAINEE"); break;
		case DEBUG:
			strcpy(levelString, "DEBUG"); break;
		default: break;
	}
	sprintf(msgBuffer, "Level: %s 25fps", (char*)levelString /* set fps here */);
	sprintf(info[0], (char*)msgBuffer);

	//write current camera name to info buffer
	char name[12];
	strcpy(name, currentCamera->getName().c_str());
	sprintf(msgBuffer, "Camera: %s", (char*)name);
	sprintf(info[CAM_NAME], (char*)msgBuffer);

	//write camera position to info buffer
	currentCamera->getLocation(x, y, z);
	sprintf(msgBuffer, "%6.0f %6.0f %6.0f", x, y, z);
	sprintf(info[CAM_LINE], (char*)msgBuffer);

	//write warbird position to info buffer
	warbird->getLocation(x, y, z);
	sprintf(msgBuffer, "%6.0f %6.0f %6.0f", x, y, z);
	sprintf(info[WAR_LINE], (char*)msgBuffer);
	
	//write U.Missile position to info buffer
	missileSites.at(U_MISSILE)->getLocation(x, y, z);	//TODO: FIX BUG!!!
	sprintf(msgBuffer, "%6.0f %6.0f %6.0f", x, y, z);
	sprintf(info[U_MISS_LINE], (char*)msgBuffer);

	//write T.Missile position to info buffer
	missileSites.at(T_MISSILE)->getLocation(x, y, z);
	sprintf(msgBuffer, "%6.0f %6.0f %6.0f", x, y, z);
	sprintf(info[T_MISS_LINE], (char*)msgBuffer);
}

void printText(){
	int yOffset = INFO_HEIGHT - 40, xOffset = -80;

	for (int i=0; i<NUM_MSGS; i++){
		for (int j=0; j<MSG_LENGTH; j++){
			glRasterPos3i(xOffset, yOffset, 0);
			glutBitmapCharacter(GLUT_BITMAP_8_BY_13, info[i][j]);
			
			xOffset += 12;
		}
		xOffset = -80;
		yOffset -= 42;
	}
}

void toggleGravity(bool gravity){
	warbird->setGravity(gravity);
	if (!torpedos.empty()){
		vector<Torpedo *>::iterator i;
		for (i=torpedos.begin(); i<torpedos.end(); i++)
			(*i)->setGravity(gravity);
	}

	if(gravity)	cout<< "Gravity ON" <<endl;
	else cout<< "Gravity OFF" <<endl;
}

void keyDown(unsigned char key, int x, int y){		
	static int tq;
	
	switch(key){
		case 'q': 
			cleanUpAndExit(); break;

		case 'p': 
			togglePlanetCamera(); break;

		case 'w':			
			if ( ++warpIterator == planetCameras.end())
				warpIterator = planetCameras.begin();

			warbird->warp(warpIterator);
			break;

		case 'f': 
			warbird->fireTorpedo();
			break;

		case 'g':
			gravityOn = !gravityOn;
			toggleGravity(gravityOn);
			break;

		case 'v':
			toggleFrontShipCamera();			
			break;

		case 't': 
			tq = (tq + 1) % NUM_TIMERS;

			switch (tq){
				case 0:
					timeQuantum = ACE;
					cout<<"ACE Mode"<<endl;
					break;
				case 1:
					timeQuantum = PILOT;
					cout<<"PILOT Mode"<<endl;
					break;
				case 2:
					timeQuantum = TRAINEE;
					cout<<"TRAINEE Mode"<<endl;
					break;
				case 3:
					timeQuantum = DEBUG;
					cout<<"DEBUG Mode"<<endl;
					break;
				default: 
					timeQuantum = ACE;
					cout<<"ACE Mode"<<endl;
			}
			break;
		default: break;
	}
}

void specialDown(int key, int x, int y){		
	if (glutGetModifiers() == GLUT_ACTIVE_CTRL)
		keyBuffer[CTRL_KEY] = true;
	if (key == GLUT_KEY_UP)
		keyBuffer[UP_KEY] = true;
	if (key == GLUT_KEY_DOWN)
		keyBuffer[DOWN_KEY] = true;
	if (key == GLUT_KEY_LEFT)
		keyBuffer[LEFT_KEY] = true;
	if (key == GLUT_KEY_RIGHT)
		keyBuffer[RIGHT_KEY] = true;
}

void specialUp(int key, int x, int y){
	if (glutGetModifiers() != GLUT_ACTIVE_CTRL)
		keyBuffer[CTRL_KEY] = false;
	if (key == GLUT_KEY_UP)
		keyBuffer[UP_KEY] = false;
	if (key == GLUT_KEY_DOWN)
		keyBuffer[DOWN_KEY] = false;
	if (key == GLUT_KEY_LEFT)
		keyBuffer[LEFT_KEY] = false;
	if (key == GLUT_KEY_RIGHT)
		keyBuffer[RIGHT_KEY] = false;
}

void executeSpecialKeys(){
			
	if (keyBuffer[CTRL_KEY]){
		if (keyBuffer[UP_KEY])
			warbird->pitchDown(WARBIRD_ROTATE_SPEED);
		if (keyBuffer[DOWN_KEY])
			warbird->pitchUp(WARBIRD_ROTATE_SPEED);
		if (keyBuffer[LEFT_KEY])
			warbird->rollLeft(WARBIRD_ROTATE_SPEED);
		if (keyBuffer[RIGHT_KEY])
			warbird->rollRight(WARBIRD_ROTATE_SPEED);
	}
	else{
		if (keyBuffer[UP_KEY])
			warbird->thrustUp(WARBIRD_THRUST_SPEED);
		if (keyBuffer[DOWN_KEY])
			warbird->thrustBack(WARBIRD_THRUST_SPEED);
		if (keyBuffer[LEFT_KEY])
			warbird->yawLeft(WARBIRD_ROTATE_SPEED);
		if (keyBuffer[RIGHT_KEY])
			warbird->yawRight(WARBIRD_ROTATE_SPEED);
	}
	
}

void updateAll(int i){

	executeSpecialKeys();
	
	//Order of updates is crucial!
	updatePlanets();
	updateMoons();
	updateMissileSites();
	warbird->move();	
	updateTorpedos();
	updateChaseCameras();

	checkForCollisions();

	redisplayAll();	

	glutTimerFunc(timeQuantum, updateAll, 1);
}

void updatePlanets(){
	if (!planets.empty()){
		vector<Planet*>::iterator i;
		for (i=planets.begin(); i<planets.end(); i++)
			(*i)->move();
	}
}
void updateMoons(){
	if (!moons.empty()){
		vector<Moon*>::iterator i;
		for (i=moons.begin(); i<moons.end(); i++)
			(*i)->move();
	}	
}
void updateMissileSites(){
	if (!missileSites.empty()){
		vector<MissileBattery*>::iterator i;
		for (i=missileSites.begin(); i<missileSites.end(); i++){
			(*i)->move(); 

			if ((*i)->distance(warbird) <= (*i)->getdetectionRadius())
				(*i)->fireTorpedo();
		}
	}	
}
void updateTorpedos(){	
	if (!torpedos.empty()){
		vector<Torpedo *>::iterator i;
		for (i=torpedos.begin(); i<torpedos.end(); i++)
			(*i)->move();
	}	
}
void updateChaseCameras(){
	if (!chaseCameras.empty()){
		vector<ChaseCamera *>::iterator i;
		for (i=chaseCameras.begin(); i<chaseCameras.end(); i++)
			(*i)->move();
	}	
}

void checkForCollisions(){		
	checkTorpedoCollisions();
	checkWarbirdCollisions();
}

void checkTorpedoCollisions(){

	if(!torpedos.empty()){

		vector<Torpedo*>::iterator i;
		for (i=torpedos.begin(); i<torpedos.end(); i++){

			if ((*i)->isArmed()){
				//check collision against sun
				if ( (*i)->checkForCollisions(ruber) )
					(*i)->setExploding(true);
					
				//check collision against warbird
				if ( (*i)->checkForCollisions(warbird) ){
					(*i)->setExploding(true);
					warbird->setExploding(true);
				}
					
				//check collision against planets
				if(!planets.empty()){
					vector<Planet*>::iterator a;
					for (a=planets.begin(); a<planets.end(); a++){
						if( (*i)->checkForCollisions((*a)) )
							(*i)->setExploding(true);
					}
				}

				//check collision agains moons
				if(!moons.empty()){
					vector<Moon*>::iterator b;
					for (b=moons.begin(); b<moons.end(); b++){
						if ( (*i)->checkForCollisions((*b)) )
							(*i)->setExploding(true);
					}
				}

				//check collision against missile batteries
				if(!missileSites.empty()){
					vector<MissileBattery*>::iterator c;
					for (c=missileSites.begin(); c<missileSites.end(); c++){
						if ( (*i)->checkForCollisions((*c)) ){
							(*i)->setExploding(true);
							(*c)->setExploding(true);
						}
					}
				}
			}

		}
	}
}
void checkWarbirdCollisions(){

	//check collision against sun
	if ( warbird->checkForCollisions(ruber) )
		warbird->setExploding(true);

	//check collision against planets
	if(!planets.empty()){
		vector<Planet*>::iterator i;
		for (i=planets.begin(); i<planets.end(); i++){
			if( warbird->checkForCollisions((*i)) )
				warbird->setExploding(true);
		}
	}
	//check collision against moons
	if(!moons.empty()){
		vector<Moon*>::iterator j;
		for (j=moons.begin(); j<moons.end(); j++){
			if ( warbird->checkForCollisions((*j)) )
				warbird->setExploding(true);
		}
	}

	//check collision against missile batteries
	if(!missileSites.empty()){
		vector<MissileBattery*>::iterator k;
		for (k=missileSites.begin(); k<missileSites.end(); k++){
			if ( warbird->checkForCollisions((*k)) ){
				warbird->setExploding(true);
				(*k)->setExploding(true);
			}
		}
	}

}

void createSpaceObjects(){
	
	enum {RUBER, UNUM, U_MISSILE, U_PRIMUN, U_SECUNDO, DUO, TRES, T_PRIMUN, T_SECUNDO, 
		T_TERTIA, T_MISSILE, T_QUARTUM, QUATTUOR, Q_PRIMUN, WARBIRD};

	//initial object locations
	GLfloat startLoc[15][3] = 
	{
		{0, 0, 0},			//Ruber
		{4000, 0, 0},		//Unum
		{320, 0, 0},		//U.missile (from Unum)
		{800, 0, 0},		//U.Primun (from Unum)
		{1000, 0, 0},		//U.Secundo	(from Unum)
		{-7000, 0, 0},		//Duo
		{0, 0, 12000},		//Tres
		{0, 0, 1800},		//T.Primun (from Tres)
		{0, 0, 2000},		//T.secundo (from Tres)
		{0, 0, 2300},		//T.Tertia (from Tres)
		{0, 0, 105},		//T.missile (from T.Quartum)
		{0, 0, 2700},		//T.Quartum (from Tres)
		{0, 0, -20000},		//Quattuor
		{0, 0, -1000},		//Q.Primun (from Quattuor)
		{5000, 1000, -5000}	//Warbird
	};

	//create sun
	ruber = new Sun("Ruber", 2000, red);

	//create warbird
	warbird = new PlayerShip("Warbird", startLoc[WARBIRD]);

	//create planets	
	Planet * unum		= new Planet("Unum", 300, green, ruber, startLoc[UNUM], 0.4500);		
	Planet * duo		= new Planet("Duo", 400, blue, ruber, startLoc[DUO], 0.2250);	
	Planet * tres		= new Planet("Tres", 800, magenta, ruber, startLoc[TRES], 0.1125);
	Planet * quattuor	= new Planet("Quattuor", 500, cyan, ruber, startLoc[QUATTUOR], 0.0750);

	//create moons
	Moon * uPrimun	= new Moon("U.Primun", 50, white, unum, startLoc[U_PRIMUN], 1.125);
	Moon * uSecundo = new Moon("U.Secundo", 50, gray, unum, startLoc[U_SECUNDO], 0.7500);
	Moon * tPrimun	= new Moon("T.Primun", 50, white, tres, startLoc[T_PRIMUN], 0.7500);
	Moon * tSecundo = new Moon("T.Secundo", 50, silver, tres, startLoc[T_SECUNDO], 0.5625);
	Moon * tTertia	= new Moon("T.Tertia", 80, gray, tres, startLoc[T_TERTIA], 0.4500);
	Moon * tQuartum	= new Moon("T.Quartum", 100, dark_gray, tres, startLoc[T_QUARTUM], 0.3214);
	Moon * qPrimun	= new Moon("Q.Primun", 100, white, quattuor, startLoc[Q_PRIMUN], 0.4500);

	//create missile batteries
	MissileBattery * uMissile = new MissileBattery("U.Missile", red, unum, warbird, 120, 3000, startLoc[U_MISSILE]);
	MissileBattery * tMissile = new MissileBattery("T.Missile", red, tQuartum, warbird, 240, 6000, startLoc[T_MISSILE]);			

	//store planets in container
	planets.push_back(unum);
	planets.push_back(duo);
	planets.push_back(tres);
	planets.push_back(quattuor);

	//store moons in container
	moons.push_back(uPrimun);
	moons.push_back(uSecundo);
	moons.push_back(tPrimun);
	moons.push_back(tSecundo);
	moons.push_back(tTertia);
	moons.push_back(tQuartum);
	moons.push_back(qPrimun);

	//store missile sites in container
	missileSites.push_back(uMissile);
	missileSites.push_back(tMissile);
}

void createCameras(){

	enum {EYE, LOOKAT, UP};	
	GLdouble front[3][3] ={
		{0.0, 0.0, 40000.0},
		{0.0, 0.0, 0.0},
		{0.0, 1.0, 0.0} 
	};
	GLdouble top[3][3] ={
		{0.0, 40000.0, 0.0},
		{0.0, 0.0, 0.0},
		{0.0, 0.0, -1.0} 
	};	

	//create all cameras
	enum{UNUM, DUO, TRES, QUATTUOR};
	topCamera = new Camera("Top View", top[EYE], top[LOOKAT], top[UP]);
	Camera * frontCamera = new Camera("Front View", front[EYE], front[LOOKAT], front[UP]);
	ChaseCamera * warbirdCamera = new ChaseCamera("Ship Camera", warbird, 1118.0340, 26.5651, 15.0);
	ChaseCamera * unumCamera = new ChaseCamera("Unum Camera", planets.at(UNUM), 2000.0, 90.0, 0.0);
	ChaseCamera * duoCamera = new ChaseCamera("Duo Camera", planets.at(DUO), 2000.0, 90.0, 0.0); 
	ChaseCamera * tresCamera = new ChaseCamera("Tres Camera", planets.at(TRES), 5000, 90.0, 0.0);
	ChaseCamera * quattuorCamera = new ChaseCamera("Quattuor Camera", planets.at(QUATTUOR), 3000.0, 90.0, 0.0);

	//container for toggling between ship view and front view
	frontShipCameras.push_back(frontCamera);
	frontShipCameras.push_back(warbirdCamera);

	//container for cycling through planet views
	planetCameras.push_back(unumCamera);
	planetCameras.push_back(duoCamera);
	planetCameras.push_back(tresCamera);
	planetCameras.push_back(quattuorCamera);

	//container for updating movable chase cameras
	chaseCameras.push_back(warbirdCamera);
	chaseCameras.push_back(unumCamera);
	chaseCameras.push_back(duoCamera);
	chaseCameras.push_back(tresCamera);
	chaseCameras.push_back(quattuorCamera);

	//container for easy deletion upon quit. Memory cost is negligible.
	allCameras.push_back(topCamera);
	allCameras.push_back(frontCamera);
	allCameras.push_back(warbirdCamera);
	allCameras.push_back(unumCamera);
	allCameras.push_back(duoCamera);
	allCameras.push_back(tresCamera);
	allCameras.push_back(quattuorCamera);

	cout<<frontCamera->getName()<<endl;
}

void setCurrentCamera(){
	switch(lastSelectedCamType){
		case FRONT_SHIP_VIEW: 
			(*frontShipCamIterator)->setCameraView();
			currentCamera = (*frontShipCamIterator);
			break;
		case PLANET_VIEW:
			(*planetCamIterator)->setCameraView();
			currentCamera = (*planetCamIterator);
			break;
	}

}

void toggleFrontShipCamera(){
	if (lastSelectedCamType == FRONT_SHIP_VIEW){
		frontShipCamIterator++;

		if(frontShipCamIterator == frontShipCameras.end())
			frontShipCamIterator = frontShipCameras.begin();
	}
	else{
		lastSelectedCamType = FRONT_SHIP_VIEW;
	}
}

void togglePlanetCamera(){
	if (lastSelectedCamType == PLANET_VIEW){		
		planetCamIterator++;

		if(planetCamIterator == planetCameras.end())
			planetCamIterator = planetCameras.begin();
	}
	else{
		lastSelectedCamType = PLANET_VIEW;
	}
}

void setLighting(){
/* Set Lighting for the Ruber solar system */

	// light values
	static GLfloat heavenLightColor[4] = { 0.6, 0.6, 0.6, 1.0 };//white light
	static GLfloat ruberLightColor[4] = { 1.0, 0.5, 0.4, 1.0 }; //reddish light
	static GLfloat ambient[4] = { 0.1, 0.1, 0.1, 1.0 };
	GLfloat  specular[] = { 1.0f, 1.0f, 1.0f, 1.0f};
	GLfloat  specularReflection[] =  { 1.0f, 1.0f, 1.0f, 1.0f };

	//light positions
	static GLfloat heavenLightPos[4] = {1.0, 1.0, 1.0, 0.0 };	//directional light
	static GLfloat ruberLightPos[4] = {0.0, 0.0, 0.0, 1.0 };	// point light	
	
	glEnable(GL_DEPTH_TEST);  
	glShadeModel(GL_SMOOTH);
	glEnable(GL_LIGHTING);
	glEnable(GL_LIGHT0);
	glEnable(GL_LIGHT1);
	glEnable(GL_COLOR_MATERIAL);
	
	// set light materials
	glLightModelfv(GL_LIGHT_MODEL_AMBIENT, ambient);

	glLightfv(GL_LIGHT0, GL_DIFFUSE, heavenLightColor);
	glLightfv(GL_LIGHT0, GL_POSITION, heavenLightPos);
	glLightfv(GL_LIGHT0,GL_SPECULAR, specular);
	glMaterialfv(GL_FRONT, GL_SPECULAR,specularReflection);
	glMateriali(GL_FRONT, GL_SHININESS,128);

	glLightfv(GL_LIGHT1, GL_DIFFUSE, ruberLightColor);
	glLightfv(GL_LIGHT1, GL_POSITION, ruberLightPos);        
}

void redisplayAll(){
	glutSetWindow(parentWindow);  
	glutPostRedisplay();
	glutSetWindow(gameWindow);
	glutPostRedisplay();
	glutSetWindow(topViewWindow);   
	glutPostRedisplay(); 
	glutSetWindow(infoWindow);
	glutPostRedisplay();
}

void cleanUpAndExit(){	
			
	deleteCameras();
	//deleteTorpedos();
	deleteMissileSites();
	deleteMoons();
	deletePlanets();	
	delete ruber;
	delete warbird;

	cout<<"\nROMULAN TARGET PRACTICE Exited"<<endl;
	exit(0);
}

void deleteCameras(){
	if (!allCameras.empty()){
		vector<Camera*>::iterator i;
		for (i=allCameras.begin(); i<allCameras.end(); i++)
			delete (*i);
	}
}
void deleteTorpedos(){
	if (!torpedos.empty()){
		vector<Torpedo*>::iterator i;
		for (i=torpedos.begin(); i<torpedos.end(); i++)
			delete (*i);
	}
}
void deleteMissileSites(){
	if (!missileSites.empty()){
		vector<MissileBattery*>::iterator i;
		for (i=missileSites.begin(); i<missileSites.end(); i++)
			delete (*i);
	}
}
void deleteMoons(){
	if (!moons.empty()){
		vector<Moon*>::iterator i;
		for (i=moons.begin(); i<moons.end(); i++)
			delete (*i);
	}
}
void deletePlanets(){
	if (!planets.empty()){
		vector<Planet*>::iterator i;
		for (i=planets.begin(); i<planets.end(); i++)
			delete (*i);
	}
}

#endif